プログラミング言語 Unison を知る
どうやって Unison を見つけたか
https://www.youtube.com/watch?v=vhIQZ0px-Lc
https://gyazo.com/d0e5e023526806b14063ac16104a29bf
少し調べると Roc は他の FP とそこまで大差が無かった 一方、Unison は今までのプログラミング言語や開発スタイルを アンラーニング にする必要があるぐらい根本から違った なので、とりあえず学んでみる
特徴
code:u(hs)
double : Nat -> Nat
double x =
x * 2
code:u(hs)
use List ++ +: :+
head :+ 5
code:u(hs)
helloWorld : '{IO, Exception} () -- この ' が遅延評価を表す
helloWorld = do printLine "Hello World"
do はそれ以降を遅延計算するキーワード
code:u(hs)
Text.filter isDigit "abc_10203_def" |> Text.split ?0
code:u(hs)
Pattern.run (Pattern.capture (Pattern.many (chars "🍎🍏"))) "🍏🍎🍎🍏123"
code:u(hs)
Nat.range 0 10
|> List.map (x -> x Nat.* 100)
|> List.filter (const true)
|> List.foldLeft (Nat.+) 0
code:u(hs)
Optional.filter Nat.isEven <| Some 5
純粋関数型なので、依存している実装が変更されてない限りはテストがキャッシュされる
標準ライブラリ(lib/base)の機能が豊富
例えば以下のような increment 関数は
code:u(hs)
increment : Nat -> Nat
increment x = x + 1
以下のように管理される
code:u(hs)
コードベースを自身で直接管理することはできない(∵ ソースファイルは存在しない)
一時バッファである .u ファイルにコードを記述し、後述する ucm(Unison Codebase Management)を用いてコードベースに追加 する もちろん Git / GitHub は使えないので ucm が代替する(後述)
変更管理や依存関係の解決、分散実行が容易、最低限の インクリメンタルビルド が可能になったりと様々なメリットがある サンプルコード
if / else
code:u(hs)
isEven num =
if mod num 2 === 0 then "even" else "odd"
code:u(hs)
isEven num = match num with
n | mod n 2 === 0 -> "even"
_ -> "odd"
code:u(hs)
isEven = cases
n | mod n 2 === 0 -> "even"
_ -> "odd"
code:u(hs)
match Some 12 with
Optional.None -> "none"
-- ガードパターン
Some n| Nat.isEven n -> "n is a variable and | is a pattern guard"
-- as パターン
opt@(Some n) -> "opt binds to the entire optional value"
型宣言
code:u(hs)
type LivingThings
= Animal | Plant | Fungi | Protists | Monera
code:u(hs)
type Pet = {
age : Nat,
species : Text,
}
例外処理
code:u(hs)
nonZero : Nat ->{Exception} Nat
nonZero =
use Nat ==
cases
n
| n == 0 -> Exception.raise (Generic.failure "Zero was found" n)
| otherwise -> n
code:u(hs)
catch do nonZero 0
code:u(hs)
getRandomElem : a ->{Abort, Random} a getRandomElem list =
use unison_base_4_8_0.abilities.Random natIn
randomIndex = natIn 0 (List.size list)
List.at! randomIndex list
code:u(hs)
toOptional! do splitmix 42 do getRandomElem 1, 2, 3 toOptional!: '{g Abort} a -> {g} Optional a
Abort ability を Optional に変換する
splitmix : Nat ->'{g, Random} t -> {g} t
Ability の定義
code:u(hs)
structural ability Abort where
abort : {Abort} a
code:u(hs)
structural ability Exception where
raise : Failure ->{Exception} x
structural は 構造的型付け で型定義を行うキーワード code:u(hs)
exampleGet : '{IO, Exception, Threads} HttpResponse
exampleGet _ =
use unison_base_4_8_0.IO.net.URI parse
req = do Http.get uri
Http.run req
code:u(hs)
printResponse : '{IO, Exception} ()
printResponse =
use unison_base_4_8_0.abilities Random.run
use systemfw_concurrent_7_2_1 Threads.run
do
Random.run do
Threads.run do
response = exampleGet ()
printLine (bodyText response)
ucm
Git 相当の操作や依存関係のインストール、コード検索など、あらゆる操作を行う対話型 CLI Unison への Push 操作などもすべて ucm で行う
ucm を実行して立ち上げる
ucm コマンド例
help: ucm コマンド一覧
auth.login: ucm と Unison Share のアカウントを連携
プロジェクト関連
projects / project.list: プロジェクトの一覧
project.create: プロジェクトの作成
project.delete: プロジェクトの削除
switch: プロジェクトの切り替え
lib.install: サードパーティライブラリのインストール
ls: 名前空間を一覧表示する
コードベース関連
view: 指定された名前の定義確認`
add / update: 一時バッファのコードをすべてコードベースに反映する
--- より下の行は無視される
delete: 指定した定義の削除
edit: 編集のため、一時バッファに指定された名前の定義をコピーする
reflog: 現在のブランチの変更差分を表示
find: コードベースで定義されている型・関数の検索
docs: コードドキュメント参照
ブランチ関連
branches / branch.list: ブランチの一覧
merge: ブランチのマージ
実行関連
run: 指定された {IO,Exception} () の関数を実行する(e.g. printLine を用いた関数)
compile: 指定された '{IO, Exception} () の関数をコンパイルして実行ファイル(.uc)ファイルを生成
生成したファイルは $ ucm run.compiled で実行可能
テスト関連
test: テスト実行
とりあえず動かしてみよう
所感
新しいプログラミング言語の可能性を見れた
ucm の操作を Tools として認識させればいけるか
しかし、IF が AI_Agent で内部で Unison のようなコードベース管理をするような言語というのは面白そう ハッシュ管理がベストな解決策なのかは分からないが
Q&A
デプロイはどうするの?
学べる教材はあるの?
Web アプリケーションを開発してみたい場合は Unison Cloud のチュートリアルがあります
どのように開発を進めたら良いの?
公式ドキュメントの以下のページが参考になります
実装をいちいち ucm 経由で確認するの面倒じゃない?
デスクトップアプリから update したものに関しては確認できます
参考